package com.zipking.cloud.springbootmybatis.util;

import com.zipking.cloud.springbootmybatis.model.PageReq;
import org.slf4j.Logger;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;

public interface BatchQueryPageUtils<T> {

    /**
     * 批量处理，分页+多线程处理
     * @param poolExecutor       线程池
     * @param pageSize           每页查询的大小
     * @param perThreadCount     每个线程处理的记录数
     * @param queryTotalNumParam 查询记录总数的参数，必须继承PageReq
     * @param queryDataParam     查询分页列表的参数，必须继承PageReq
     * @param logger             子类的日志对象
     * @param otherParam         其他参数，需要给processLongTimeLogic方法传递的参数
     * @throws InterruptedException
     */
    default int batchProcess(ThreadPoolExecutor poolExecutor, int pageSize, int perThreadCount, Object queryTotalNumParam, PageReq queryDataParam, Logger logger, Map<String, Object> otherParam) throws InterruptedException {
        int pageIndex = 0;
        int pageNum = 1;
        int totalNum = queryTotalNum(queryTotalNumParam);
        if (totalNum == 0) {
            logger.info("需要处理的数据数量为0");
            return 0;
        }
        try {
            while (pageNum <= (totalNum % pageSize == 0 ? (totalNum / pageSize) : (totalNum / pageSize + 1))) {
                pageIndex = pageSize * (pageNum - 1);
                queryDataParam.setPageIndex(pageIndex);
                queryDataParam.setPageRows(pageSize);
                List<T> list = queryDataListByPage(queryDataParam);
                int batchNum = list.size();
                final CountDownLatch cdl = new CountDownLatch((batchNum % perThreadCount) == 0 ? (batchNum / perThreadCount) : (batchNum / perThreadCount + 1)); //计数器
                for (int j = 1; j <= (batchNum % perThreadCount == 0 ? (batchNum / perThreadCount) : (batchNum / perThreadCount + 1)); j++) {
                    //每100条一个线程处理
                    int start = perThreadCount * (j - 1);
                    int end = (batchNum - start) >= perThreadCount ? (start + perThreadCount) : batchNum;
                    int pageNums = pageNum;
                    poolExecutor.submit(() -> {
                        logger.info("第{}页的第{}-{}条数据处理开始", pageNums, start + 1, end);
                        //处理其他长时间的逻辑
                        processLongTimeLogic(list.subList(start, end), otherParam);
                        logger.info("第{}页的第{}-{}条数据处理结束", pageNums, start + 1, end);
                        cdl.countDown();
                    });
                }
                cdl.await();
                pageNum++;
            }
        } catch (Exception e) {
            logger.error("批量处理数据异常", e);
            throw e;
        }
        return totalNum;
    }

    /**
     * 查询记录总数
     *
     * @param queryParam
     * @return
     */
    int queryTotalNum(Object queryParam);

    /**
     * 分页查询数据
     *
     * @param queryDataParam
     * @return
     */
    List<T> queryDataListByPage(PageReq queryDataParam);

    /**
     * 处理长时间业务逻辑
     *
     * @param list  处理的数据列表
     * @param otherParam 其他参数
     */
    void processLongTimeLogic(List<T> list, Map<String, Object> otherParam);
}
